package org.jeecg.modules.zhima.base.shiro.service;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.zhima.base.common.Constant.Constant;
import org.jeecg.modules.zhima.base.common.Constant.RedisKey;
import org.jeecg.modules.zhima.base.util.RedisUtil;
import org.jeecg.modules.zhima.base.util.ServletUtils;
import org.jeecg.modules.zhima.center.entity.UmsMember;
import org.jeecg.modules.zhima.portal.service.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author lixiao
 * @version 1.0
 * @date 2020/4/15 11:45
 */
@Service
public class TokenService {

    @Resource
    private IUserService userService;

//    @Resource
//    private PermissionsService permissionsService;

    @Resource
    private RedisUtil redisCache;

    public static final Long EXPIRATION = 604800l; //JWT的超期限时间(60*60*24)
    public static final String TYPE_MOBILE = "mobile";
    public static final String TYPE_WEIXIN = "weixin";
    public static final String KEY = "key";
    public static final String USER_ID = "userId";

    /**
     * 获取当前登录的User对象
     *
     * @return User
     */
    public UmsMember getLoginUser() {
        // 获取token
        String token = getToken(ServletUtils.getRequest());
        if (StringUtils.isEmpty(token)){
            return null;
        }
        String type = getType(token);
        String key = null;
        if (type.equals(TYPE_MOBILE)){
            key = getPhone(token);
        }else if(type.equals(TYPE_WEIXIN)){
            key = getWxOpenId(token);
        }
//        // 获取手机号
//        String phone = getPhone(token);
        // 获取缓存loginUserKey
        String loginUserKey = RedisKey.getLoginUserKey(key);
        // 获取缓存loginUser
        Object cacheObject = redisCache.get(loginUserKey);
        if (cacheObject == null) {
            // 获取当前登录用户
            UmsMember user = null;
            if (type.equals(TYPE_MOBILE)){
                user = userService.getMemberByPhone(key);
            }else if(type.equals(TYPE_WEIXIN)){
                user = userService.getMemberByWxOpenId(key);
            }
//            UmsMember user = userService.getMemberByPhone(phone);
            // 缓存当前登录用户
            redisCache.set(loginUserKey, user);
            return user;
        }
        return (UmsMember) cacheObject;
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的类型
     */
    public String getType(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("type").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的用户手机号
     */
    public String getPhone(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("phone").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的用户手机号
     */
    public String getKey(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(KEY).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的用户id
     */
    public String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(USER_ID).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return token中包含的用户id
     */
    public String getWxOpenId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("wxOpenId").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取当前登录用户的token,如果token为null则获取refreshToken
     *
     * @param request HttpServletRequest
     * @return token
     */
    public String getToken(HttpServletRequest request) {
        String token = request.getHeader(Constant.TOKEN_HEADER_NAME);
        if (StringUtils.isEmpty(token)) {
            return request.getParameter("refreshToken");
        } else {
            return token;
        }
    }

    /**
     * @param wxOpenId 微信id
     * @param userId 用户id
     * @param time   token的有效时间 单位:毫秒
     * @return 加密的token
     */
    public String createTokenByWX(String wxOpenId, Integer userId, Long time) {
        Date date = new Date(System.currentTimeMillis() + time);
        Algorithm algorithm = Algorithm.HMAC256(wxOpenId);
        return JWT.create()
                .withClaim("type", TYPE_WEIXIN)
                .withClaim(KEY, wxOpenId)
                .withClaim("wxOpenId", wxOpenId)
//                .withClaim("wxOpenId", wxOpenId)
                .withClaim(USER_ID, String.valueOf(userId))
                .withExpiresAt(date)
                .sign(algorithm);
    }

    /**
     * @param phone  用户名/手机号
     * @param userId 用户id
     * @param secret 用户的密码
     * @param time   token的有效时间 单位:毫秒
     * @return 加密的token
     */
    public String createToken(String phone, Integer userId, String secret, Long time) {
        Date date = new Date(System.currentTimeMillis() + time);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        return JWT.create()
                .withClaim("type", TYPE_MOBILE)
                .withClaim(KEY, phone)
                .withClaim("phone", phone)
//                .withClaim("phone", phone)
                .withClaim(USER_ID, String.valueOf(userId))
                .withExpiresAt(date)
                .sign(algorithm);
    }

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public boolean verify(String token, String secret) {
        try {
            // 根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(KEY, getKey(token))
                    .withClaim(USER_ID, getUserId(token))
                    .build();
            // 效验TOKEN
            verifier.verify(token);
            return true;
        } catch (JWTVerificationException exception) {
            return false;
        }
    }

}
